{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction to atomman: LAMMPS data file conversions\n",
    "__Lucas M. Hale__, [lucas.hale@nist.gov](mailto:lucas.hale@nist.gov?Subject=ipr-demo), _Materials Science and Engineering Division, NIST_.\n",
    "    \n",
    "[Disclaimers](http://www.nist.gov/public_affairs/disclaimer.cfm) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Introduction<a id='section1'></a>\n",
    "\n",
    "The atom_data format is the atomic data files used by LAMMPS for importing initial configurations.  Currently, atomman offers partial support for the atom_data format based on atomman's core features.  See the [LAMMPS documentation](https://lammps.sandia.gov/doc/read_data.html) for more details on the format."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The supported atom_data fields are\n",
    "\n",
    "- Header sections:\n",
    "\n",
    "    - __atoms__: number of atoms. Required during load, always listed during dump.\n",
    "    \n",
    "    - __atom types__: number of atom types.  Required during load if Masses is included, always listed during dump.\n",
    "    \n",
    "    - __xlo xhi__: simulation box boundaries in x dimension. Required during load, always listed during dump.\n",
    "    \n",
    "    - __ylo yhi__: simulation box boundaries in y dimension. Required during load, always listed during dump.\n",
    "    \n",
    "    - __zlo zhi__: simulation box boundaries in z dimension. Required during load, always listed during dump.\n",
    "    \n",
    "    - __xy xz yz__: simulation box tilt factors for triclinic system. Optional during load, listed during dump only if the tilt factors have non-zero values.\n",
    "    \n",
    "- Body sections:\n",
    "\n",
    "    - __Atoms__: lists per-atom properties associated with each atom.  The mapping of LAMMPS<->atomman representations of the per-atom properties can be found in atomman.load.atom_data.atoms_prop_info and atomman.dump.atom_data.atoms_prop_info.  Required during load, always listed during dump.\n",
    "    \n",
    "    - __Velocities__: list per-atom velocity properties associated with each atom.  The mapping of LAMMPS<->atomman representations of the per-atom properties can be found in atomman.load.atom_data.velocities_prop_info and  atomman.dump.atom_data.velocities_prop_info. Optional during load, will be listed during dump if 'velocity' is set as a per-atom property.\n",
    "     \n",
    "    - __Masses__: masses per each atom type. Optional during load, where values are saved to system.masses.  As for dump, the Masses section is never included because atomman.lammps.Potential generates LAMMPS mass input command lines.  See Section 3.4 below for more details.\n",
    "\n",
    "Notes on ignored fields:\n",
    "\n",
    "- The __Pair Coeffs__ and __PairIJ Coeffs__ fields are ignored as potential parameters are handled with the atomman.lammps.Potential class.\n",
    "\n",
    "- Support for __bonds, angles, dihedrals, impropers, ellipsoids, lines, triangles,__ and __bodies__ would require defining how to represent these as objects in atomman.  Extending support is possible, but only if there is enough interest and help from experts of these data types."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Library Imports**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "atomman version = 1.4.0\n",
      "Notebook executed on 2021-08-04\n"
     ]
    }
   ],
   "source": [
    "# Standard Python libraries\n",
    "import os\n",
    "import datetime\n",
    "\n",
    "# http://www.numpy.org/\n",
    "import numpy as np\n",
    "\n",
    "import atomman as am\n",
    "import atomman.lammps as lmp\n",
    "import atomman.unitconvert as uc\n",
    "\n",
    "# Show atomman version\n",
    "print('atomman version =', am.__version__)\n",
    "\n",
    "# Show date of Notebook execution\n",
    "print('Notebook executed on', datetime.date.today())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. atomman.load('atom_data')<a id='section2'></a>\n",
    "\n",
    "*Update version 1.3.0*: Support for image flags, Masses, and atom_style values listed in the data file are added.  Errors returned by the method are updated to be more meaningful. \n",
    "\n",
    "Parameters\n",
    "\n",
    "- **data** (*str or file-like object*) The atom data content to read.  Can be str content, path name, or open file-like object.\n",
    "\n",
    "- **pbc** (*list of bool*) Three boolean values indicating which System directions are periodic.  Default value is (True, True, True).\n",
    "    \n",
    "- **symbols** (*tuple, optional*) Allows the list of element symbols to be assigned during loading.        \n",
    "\n",
    "- **atom_style** (*str, optional*) The LAMMPS atom_style option associated with the data file.  Optional as the data can list this value in a comment in the Atoms section header.  If not given and not found in data, the default value of 'atomic' is used.\n",
    "\n",
    "- **units** (*str, optional*) The LAMMPS units option associated with the data file.  Default value is 'metal'.\n",
    "        \n",
    "Returns\n",
    "\n",
    "- (*atomman.System*) The corresponding system.  Note all property values will be automatically converted to atomman.unitconvert's working units.\n",
    "\n",
    "Raises\n",
    "    \n",
    "- (*FileNotFoundError*) If data is (likely) a file name and no matching file is found.\n",
    "\n",
    "- (*FileFormatError*) If required content fields not found.\n",
    "\n",
    "- (*ValueError*) If atom_style is both given as a parameter and found in data, but are not the same"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.1. Basic example\n",
    "\n",
    "bcc Fe unit cell without masses and default atom_style='atomic' assumed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 2.866,  0.000,  0.000]\n",
      "bvect =  [ 0.000,  2.866,  0.000]\n",
      "cvect =  [ 0.000,  0.000,  2.866]\n",
      "origin = [ 0.000,  0.000,  0.000]\n",
      "natoms = 2\n",
      "natypes = 1\n",
      "symbols = ('Fe',)\n",
      "pbc = [ True  True  True]\n",
      "per-atom properties = ['atype', 'pos']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.000 |   0.000 |   0.000\n",
      "      1 |       1 |   1.433 |   1.433 |   1.433\n"
     ]
    }
   ],
   "source": [
    "bccFe = \"\"\"\n",
    "2 atoms\n",
    "1 atom types\n",
    "0.0000000000000 2.8665000000000 xlo xhi\n",
    "0.0000000000000 2.8665000000000 ylo yhi\n",
    "0.0000000000000 2.8665000000000 zlo zhi\n",
    "\n",
    "Masses\n",
    "\n",
    "1 55.845\n",
    "\n",
    "Atoms\n",
    "\n",
    "1 1 0.0000000000000 0.0000000000000 0.0000000000000\n",
    "2 1 1.4332500000000 1.4332500000000 1.4332500000000\n",
    "\"\"\"\n",
    "\n",
    "# Symbols specified here as file format does not include them\n",
    "system = am.load('atom_data', bccFe, symbols='Fe')\n",
    "print(system)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here, Masses were listed in the file and are saved to system.masses.  If the Masses section was not included, all system.masses values would be None."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "masses = (55.845,)\n"
     ]
    }
   ],
   "source": [
    "print('masses =',system.masses)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2. Different atom_styles"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Files that use atom_style formats different from 'atomic' can be read if either the atom_style parameter is specified or if the atom_style is listed as a comment after the \"Atoms\" header line in the data. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 2.866,  0.000,  0.000]\n",
      "bvect =  [ 0.000,  2.866,  0.000]\n",
      "cvect =  [ 0.000,  0.000,  2.866]\n",
      "origin = [ 0.000,  0.000,  0.000]\n",
      "natoms = 2\n",
      "natypes = 1\n",
      "symbols = ('Fe',)\n",
      "pbc = [ True  True  True]\n",
      "per-atom properties = ['atype', 'pos', 'charge']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.000 |   0.000 |   0.000\n",
      "      1 |       1 |   1.433 |   1.433 |   1.433\n",
      "\n",
      "system.atoms.charge = [0. 0.]\n"
     ]
    }
   ],
   "source": [
    "# Example 1 for atom_style charge\n",
    "bccFe = \"\"\"\n",
    "2 atoms\n",
    "1 atom types\n",
    "0.0000000000000 2.8665000000000 xlo xhi\n",
    "0.0000000000000 2.8665000000000 ylo yhi\n",
    "0.0000000000000 2.8665000000000 zlo zhi\n",
    "\n",
    "Masses\n",
    "\n",
    "1 55.845\n",
    "\n",
    "Atoms # charge\n",
    "\n",
    "1 1 0.0000000000000 0.0000000000000 0.0000000000000 0.0000000000000\n",
    "2 1 0.0000000000000 1.4332500000000 1.4332500000000 1.4332500000000\n",
    "\"\"\"\n",
    "\n",
    "# atom_style not needed as 'charge' is specified in the data\n",
    "system = am.load('atom_data', bccFe, symbols='Fe')\n",
    "print(system)\n",
    "\n",
    "# Show that charges are set\n",
    "print()\n",
    "print('system.atoms.charge =',system.atoms.charge)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 2.866,  0.000,  0.000]\n",
      "bvect =  [ 0.000,  2.866,  0.000]\n",
      "cvect =  [ 0.000,  0.000,  2.866]\n",
      "origin = [ 0.000,  0.000,  0.000]\n",
      "natoms = 2\n",
      "natypes = 1\n",
      "symbols = ('Fe',)\n",
      "pbc = [ True  True  True]\n",
      "per-atom properties = ['atype', 'pos', 'charge']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.000 |   0.000 |   0.000\n",
      "      1 |       1 |   1.433 |   1.433 |   1.433\n",
      "\n",
      "system.atoms.charge = [0. 0.]\n"
     ]
    }
   ],
   "source": [
    "# Example 2 for atom_style charge (no comment in data)\n",
    "bccFe = \"\"\"\n",
    "2 atoms\n",
    "1 atom types\n",
    "0.0000000000000 2.8665000000000 xlo xhi\n",
    "0.0000000000000 2.8665000000000 ylo yhi\n",
    "0.0000000000000 2.8665000000000 zlo zhi\n",
    "\n",
    "Masses\n",
    "\n",
    "1 55.845\n",
    "\n",
    "Atoms \n",
    "\n",
    "1 1 0.0000000000000 0.0000000000000 0.0000000000000 0.0000000000000\n",
    "2 1 0.0000000000000 1.4332500000000 1.4332500000000 1.4332500000000\n",
    "\"\"\"\n",
    "\n",
    "# atom_style='charge' required\n",
    "system = am.load('atom_data', bccFe, symbols='Fe', atom_style='charge')\n",
    "print(system)\n",
    "\n",
    "# Show that charges are set\n",
    "print()\n",
    "print('system.atoms.charge =',system.atoms.charge)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.3. Image flag handling\n",
    "\n",
    "Integer image flags can be added to Atoms table to move atoms to periodic replicas"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 2.866,  0.000,  0.000]\n",
      "bvect =  [ 0.000,  2.866,  0.000]\n",
      "cvect =  [ 0.000,  0.000,  2.866]\n",
      "origin = [ 0.000,  0.000,  0.000]\n",
      "natoms = 2\n",
      "natypes = 1\n",
      "symbols = ('Fe',)\n",
      "pbc = [ True  True  True]\n",
      "per-atom properties = ['atype', 'pos']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.000 |   0.000 |   0.000\n",
      "      1 |       1 |   4.300 |   1.433 |   1.433\n"
     ]
    }
   ],
   "source": [
    "bccFe = \"\"\"\n",
    "2 atoms\n",
    "1 atom types\n",
    "0.0000000000000 2.8665000000000 xlo xhi\n",
    "0.0000000000000 2.8665000000000 ylo yhi\n",
    "0.0000000000000 2.8665000000000 zlo zhi\n",
    "\n",
    "Masses\n",
    "\n",
    "1 55.845\n",
    "\n",
    "Atoms\n",
    "\n",
    "1 1 0.0000000000000 0.0000000000000 0.0000000000000 0 0 0\n",
    "2 1 1.4332500000000 1.4332500000000 1.4332500000000 1 0 0\n",
    "\"\"\"\n",
    "\n",
    "# Symbols specified here as file format \n",
    "system = am.load('atom_data', bccFe, symbols='Fe')\n",
    "print(system)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. System.dump('atom_data')<a id='section3'></a>\n",
    "\n",
    "*Updated version 1.3.0*: Parameters natypes, potential, and return_pair_info are added to provide better integration and compatibility across potentials with different pair_styles.\n",
    "\n",
    "*Updated version 1.4.0*: The return_pair_info parameter has been removed and potential commands are included in the returned info simply if potential is given.  \n",
    "\n",
    "Parameters\n",
    "        \n",
    "- **f** (*str or file-like object, optional*) File path or file-like object to write the content to.  If not given, then the content is returned as a str.\n",
    "        \n",
    "- **atom_style** (*str, optional*) The LAMMPS atom_style option associated with the data file.  If neither atom_style or potential is given, will set atom_style to 'atomic'.\n",
    "        \n",
    "- **units** (*str, optional*) The LAMMPS units option associated with the data file.  If neitherunits or potential is given, will set units 'metal'.\n",
    "        \n",
    "- **natypes** (*int, optional*) Allows the natypes value to be manually changed.  This is needed if natypes needs to be greater than the current number of atypes.  If neither natypes or potential is given, will use system.natypes.\n",
    "        \n",
    "- **potential** (*atomman.lammps.Potential, optional*) Potential-specific values of atom_style, units, and natypes can be extracted from a Potential object.  If both potential and any of the individual values are given, the individual values will be used.\n",
    "        \n",
    "- **float_format** (*str, optional*) c-style formatting string for floating point values.  Default value is '%.13f'.\n",
    "\n",
    "- **return_info** (*bool, optional*) Indicates if the LAMMPS command lines associated with reading in the file are to be returned as a str.  If potential is given, then the commands associated with the potential will be included. Default value is True.\n",
    "        \n",
    "- **safecopy** (*bool, optional*) The LAMMPS data format requires all atoms to be inside box bounds, i.e. \"wrapped\".  If safecopy is True then a copy of the system is made to keep the original unwrapped.  Default value is False.        \n",
    "        \n",
    "      \n",
    "Returns\n",
    "\n",
    "- **content** (*str, optional*) The data file contents.  Returned if f is not given.\n",
    "\n",
    "- **read_info** (*str, optional*) The LAMMPS input command lines to read the created data file in. Returned if return_info is True.  If return_pair_info is also True and potential is given, the LAMMPS input command lines for the potential are also included.\n",
    "\n",
    "Raises \n",
    "\n",
    "- (*ValueError*) If return_pair_info is True and return_info is False or potential is not given."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.1. Basic example\n",
    "\n",
    "Show dump by loading a simple data file, then dumping it to a file.\n",
    "\n",
    "__NOTE:__ It is highly recommended that the potential be given (Section 3.3.) if you are using the generated LAMMPS command lines.  Doing so ensures the proper options and order of command lines across all native LAMMPS and OpenKIM potentials currently in the NIST database. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "2 atoms\n",
      "1 atom types\n",
      "0.0000000000000 2.8665000000000 xlo xhi\n",
      "0.0000000000000 2.8665000000000 ylo yhi\n",
      "0.0000000000000 2.8665000000000 zlo zhi\n",
      "\n",
      "Atoms # atomic\n",
      "\n",
      "1 1 0.0000000000000 0.0000000000000 0.0000000000000\n",
      "2 1 1.4332500000000 1.4332500000000 1.4332500000000\n",
      "\n"
     ]
    }
   ],
   "source": [
    "bccFe = \"\"\"\n",
    "2 atoms\n",
    "1 atom types\n",
    "0.0000000000000 2.8665000000000 xlo xhi\n",
    "0.0000000000000 2.8665000000000 ylo yhi\n",
    "0.0000000000000 2.8665000000000 zlo zhi\n",
    "\n",
    "Atoms\n",
    "\n",
    "1 1 0.0000000000000 0.0000000000000 0.0000000000000\n",
    "2 1 1.4332500000000 1.4332500000000 1.4332500000000\n",
    "\"\"\"\n",
    "system = am.load('atom_data', bccFe, symbols='Fe')\n",
    "\n",
    "info = system.dump('atom_data', f='bccFe.dat')\n",
    "\n",
    "# Show created file is identical to original content\n",
    "with open('bccFe.dat') as f:\n",
    "    print(f.read())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The returned info contains LAMMPS input command lines associated with reading the file in."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# Script and atom data file prepared using atomman Python package\n",
      "\n",
      "units None\n",
      "atom_style None\n",
      "\n",
      "boundary p p p\n",
      "read_data bccFe.dat\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(info)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2. Manual modifications\n",
    "\n",
    "Now, we'll dump the same system but change natypes, units, and atom_style parameters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "2 atoms\n",
      "2 atom types\n",
      "0.0000000000000 0.2866500000000 xlo xhi\n",
      "0.0000000000000 0.2866500000000 ylo yhi\n",
      "0.0000000000000 0.2866500000000 zlo zhi\n",
      "\n",
      "Atoms # charge\n",
      "\n",
      "1 1 0.0000000000000 0.0000000000000 0.0000000000000 0.0000000000000\n",
      "2 1 0.0000000000000 0.1433250000000 0.1433250000000 0.1433250000000\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# atom_style='charge' requires per-atom property charge to be set\n",
    "system.atoms.charge = 0\n",
    "\n",
    "# units='nano' will return pos in nm instead of Angstroms\n",
    "# natypes=2 only changes the atom types header\n",
    "info = system.dump('atom_data', f='bccFe.dat', units='nano', natypes=2, atom_style='charge')\n",
    "\n",
    "# Show created file with specified changes\n",
    "with open('bccFe.dat') as f:\n",
    "    print(f.read())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Show info with specified changes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# Script and atom data file prepared using atomman Python package\n",
      "\n",
      "units None\n",
      "atom_style None\n",
      "\n",
      "boundary p p p\n",
      "read_data bccFe.dat\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(info)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.3. Integrated potential-data file handling\n",
    "\n",
    "The generation of LAMMPS data files and associated input command lines depends on properties of both the atomic configuration and the choice of interatomic potential.  To better support this fact, the atom_data dump style supports a more integrated means of generating the content.  This is handled by passing dump('atom_style') a Potential object."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define an example potential with units='nano' and atom_style='charge'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "potential_json_example_1 = \"\"\"{\n",
    "    \"potential-LAMMPS\": {\n",
    "        \"key\": \"NOKEY\",\n",
    "        \"id\": \"demo-example-1\", \n",
    "        \"potential\": {\n",
    "            \"key\": \"NOKEY\", \n",
    "            \"id\": \"demo-example\" }, \n",
    "        \"units\": \"nano\", \n",
    "        \"atom_style\": \"charge\", \n",
    "        \"atom\": { \n",
    "            \"element\": \"Fe\" },\n",
    "        \"pair_style\": {\n",
    "            \"type\": \"eam/alloy\" }, \n",
    "        \"pair_coeff\": {\n",
    "            \"term\": [\n",
    "                {\n",
    "                    \"file\": \"FeDemo.eam.alloy\" }, \n",
    "                {\n",
    "                    \"symbols\": \"True\" } ] } } }\"\"\"\n",
    "\n",
    "# Load as Potential\n",
    "potential = lmp.Potential(potential_json_example_1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Create data file and info by supplying potential"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "2 atoms\n",
      "1 atom types\n",
      "0.0000000000000 0.2866500000000 xlo xhi\n",
      "0.0000000000000 0.2866500000000 ylo yhi\n",
      "0.0000000000000 0.2866500000000 zlo zhi\n",
      "\n",
      "Atoms # charge\n",
      "\n",
      "1 1 0.0000000000000 0.0000000000000 0.0000000000000 0.0000000000000\n",
      "2 1 0.0000000000000 0.1433250000000 0.1433250000000 0.1433250000000\n",
      "\n"
     ]
    }
   ],
   "source": [
    "info = system.dump('atom_data', f='bccFe.dat', potential=potential)\n",
    "\n",
    "# Show created file uses settings from potential\n",
    "with open('bccFe.dat') as f:\n",
    "    print(f.read())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The LAMMPS command lines for the potential are now included in the returned info."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "units nano\n",
      "atom_style charge\n",
      "\n",
      "boundary p p p\n",
      "read_data bccFe.dat\n",
      "\n",
      "pair_style eam/alloy\n",
      "pair_coeff * * FeDemo.eam.alloy Fe\n",
      "mass 1 55.845\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(info)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.4. Notes on masses\n",
    "\n",
    "The Masses section is not included in the generated data file because atomman specifies mass values by creating LAMMPS mass command lines. This allows for default mass values to be defined based on the chosen potential's symbols/elements. The mass command lines can be obtained using either Potential.pair_style(), or as described in the last section.\n",
    "\n",
    "The masses that are listed in the generated mass command lines are selected according to the following order of precedence\n",
    "\n",
    "1. Any values of System.masses that are not None.\n",
    "2. The value of mass specified in a Potential data model for the atom type's symbol.\n",
    "3. The standard reference mass for the element associated with the atom type's symbol."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the previous example, the mass listed was taken as the standard reference value of Fe: 55.845.  Some potentials define specific mass values to use, which can be listed in the data model on a per model basis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# mass now explicitly defined for Fe\n",
    "potential_json_example_2 = \"\"\"{\n",
    "    \"potential-LAMMPS\": {\n",
    "        \"key\": \"NOKEY\",\n",
    "        \"id\": \"demo-example-2\", \n",
    "        \"potential\": {\n",
    "            \"key\": \"NOKEY\", \n",
    "            \"id\": \"demo-example\" }, \n",
    "        \"units\": \"nano\", \n",
    "        \"atom_style\": \"charge\", \n",
    "        \"atom\": { \n",
    "            \"element\": \"Fe\",\n",
    "            \"mass\": 55.85 },\n",
    "        \"pair_style\": {\n",
    "            \"type\": \"eam/alloy\" }, \n",
    "        \"pair_coeff\": {\n",
    "            \"term\": [\n",
    "                {\n",
    "                    \"file\": \"FeDemo.eam.alloy\" }, \n",
    "                {\n",
    "                    \"symbols\": \"True\" } ] } } }\"\"\"\n",
    "\n",
    "# Load as Potential\n",
    "potential = lmp.Potential(potential_json_example_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "units nano\n",
      "atom_style charge\n",
      "\n",
      "boundary p p p\n",
      "read_data bccFe.dat\n",
      "\n",
      "pair_style eam/alloy\n",
      "pair_coeff * * FeDemo.eam.alloy Fe\n",
      "mass 1 55.85\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# Generate data and info\n",
    "info = system.dump('atom_data', f='bccFe.dat', potential=potential)\n",
    "\n",
    "# Show that mass in info is now 55.85\n",
    "print(info)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mass values can also be manually overridden by setting system.masses.  This is particularly useful for simulations of different isotopes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "units nano\n",
      "atom_style charge\n",
      "\n",
      "boundary p p p\n",
      "read_data bccFe.dat\n",
      "\n",
      "pair_style eam/alloy\n",
      "pair_coeff * * FeDemo.eam.alloy Fe\n",
      "mass 1 57.93327443\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# Set mass for Fe-58 isotope\n",
    "system.masses = am.tools.atomic_mass('Fe-58')\n",
    "\n",
    "# Generate data and info\n",
    "info = system.dump('atom_data', f='bccFe.dat', potential=potential)\n",
    "\n",
    "# Show that mass in info is now 57.93327443\n",
    "print(info)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__cleanup__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "os.remove('bccFe.dat')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
